package com.zxmzy.scaffold.core.widget

import android.animation.ValueAnimator
import android.content.Context
import android.content.res.TypedArray
import android.graphics.*
import android.os.Build
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.View
import com.zxmzy.scaffold.core.R
import com.zxmzy.scaffold.core.ext.dp
import com.zxmzy.scaffold.core.ext.sp
import kotlin.math.abs
import kotlin.math.cos
import kotlin.math.sin


/**
 * @author zhangxiaoming
 * @date 2023/8/11
 * @description
 */
class SlideLetterView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
    //字母列表
    private var mLetters: List<String>

    //字体大小
    private var mTextSize: Int = 14.sp()

    //默认字体颜色
    private var mNormalTextColor: Int = Color.BLACK

    //选中字体颜色
    private var mSelectedTextColor: Int = Color.BLACK

    //选中字体大小
    private var mSelectedTextSize: Int = 14.sp()

    //字母间距
    private var mLetterMargin = 0

    //字母画笔
    private val mLetterPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)

    //选中字母画笔
    private val mSelectedLetterPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)

    // 波浪画笔
    private val mWavePaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)

    // 选中字体的坐标
    private var mPointX: Float = 0f // 选中字体的坐标
    private var mPointY: Float = 0f

    // 当前选中的位置
    private var mChoosePosition = 0

    // 圆形中心点X
    private var mCircleCenterX = 0f

    //提示文字的背景颜色
    private var mCircleTextBgColor = Color.BLACK

    //提示文字大小
    private var mCircleTextSize: Int = 0

    //曲线背景
    private var mWaveColor = Color.BLACK

    //控件宽度
    private var mWidth: Int = 0

    //控件高度
    private var mItemHeight: Int = 0
    private var mOldPosition = 0
    private var mNewPosition = 0

    // 计算波浪贝塞尔曲线的角弧长值
    private var ANGLE = Math.PI * 45 / 180
    private var ANGLE_R = Math.PI * 90 / 180

    // 波浪路径
    private var mWavePath: Path = Path()

    // 圆形路径
    private var mCirclePath: Path = Path()

    // 手指滑动的Y点作为中心点
    private var mCenterY = 0 //中心点Y

    // 贝塞尔曲线的分布半径
    private var mRadius = 0

    // 圆形半径
    private var mCircleRadius = 0

    // 用于过渡效果计算
    private var mRatioAnimator: ValueAnimator? = null

    // 用于绘制贝塞尔曲线的比率
    private var mRatio = 0f

    //是否是滑动
    private var isSlide = false
    private var mListener: OnTouchLetterChangeListener? = null

    init {
        mLetters = arrayListOf(*context.resources.getStringArray(R.array.slideLetters))
        val a: TypedArray = context.obtainStyledAttributes(attrs, R.styleable.SlideLetterView)
        mNormalTextColor = a.getColor(R.styleable.SlideLetterView_slvNormalTextColor, Color.BLACK)
        mSelectedTextColor =
            a.getColor(R.styleable.SlideLetterView_slvSelectedTextColor, Color.BLACK)
        mTextSize = a.getDimensionPixelSize(R.styleable.SlideLetterView_slvNormalTextSize, 14.sp())
        mSelectedTextSize =
            a.getDimensionPixelSize(R.styleable.SlideLetterView_slvSelectedTextSize, 14.sp())
        mLetterMargin = a.getDimensionPixelSize(R.styleable.SlideLetterView_slvLetterMargin, 0)
        mCircleTextBgColor = a.getColor(R.styleable.SlideLetterView_slvChooseTextColor, Color.BLACK)
        mCircleTextSize =
            a.getDimensionPixelSize(R.styleable.SlideLetterView_slvHintTextSize, 14.sp())
        mWaveColor = a.getColor(R.styleable.SlideLetterView_slvCircleBackground, Color.BLACK)
        mRadius = a.getDimensionPixelSize(R.styleable.SlideLetterView_slvRadius, 15.dp())
        mCircleRadius =
            a.getDimensionPixelSize(R.styleable.SlideLetterView_slvCircleRadius, 15.dp())
        a.recycle()
        mWavePaint.apply {
            isAntiAlias = true
            style = Paint.Style.FILL
            color = mWaveColor
        }
        mSelectedLetterPaint.apply {
            isAntiAlias = true
            style = Paint.Style.FILL
            textSize = mCircleTextSize.toFloat()
            textAlign = Paint.Align.CENTER
        }
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        mWidth = measuredWidth
        mItemHeight = mTextSize + mLetterMargin
        mPointX = mWidth - mTextSize.toFloat()
        setMeasuredDimension(mWidth, mItemHeight * mLetters.size)
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        drawLetter(canvas)
        drawWavePath(canvas)
        drawCirclePath(canvas)
        drawSelectedLetter(canvas)
    }

    override fun dispatchTouchEvent(event: MotionEvent): Boolean {
        val y = event.y
        val x = event.x
        mOldPosition = mChoosePosition
        mNewPosition = (y / (mItemHeight * mLetters.size) * mLetters.size).toInt()
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                Log.e("position", "mNewPosition:$mNewPosition")
                //限定触摸范围
                if (x < mWidth - 1.5f * mRadius) {
                    return false
                }
                if (mNewPosition > mLetters.size - 1) {
                    return false
                }
                mCenterY = y.toInt()
                startAnimator(1.0f)

                isSlide = false
                mChoosePosition = mNewPosition
                mListener?.onLetterChange(mLetters[mChoosePosition])
                invalidate()
            }
            MotionEvent.ACTION_MOVE -> {
                isSlide = true
                mCenterY = y.toInt()
                if (mOldPosition != mNewPosition) {
                    if (mNewPosition >= 0 && mNewPosition < mLetters.size) {
                        mChoosePosition = mNewPosition
                        mListener?.onLetterChange(mLetters[mNewPosition])
                    }
                }
                invalidate()
            }
            MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_UP -> {
                isSlide = false
                startAnimator(0f)
            }
        }
        return true
    }

    /**
     * 绘制字母
     */
    private fun drawLetter(canvas: Canvas) {
        for (i in mLetters.indices) {
            mLetterPaint.run {
                reset()
                isAntiAlias = true
                textAlign = Paint.Align.CENTER
                textSize = mTextSize.toFloat()
                color = mNormalTextColor
            }
            val fontMetrics = mLetterPaint.fontMetrics
            val baseline: Float = abs(-fontMetrics.bottom - fontMetrics.top)
            val pointY = mItemHeight * i + baseline + 20
            if (i == mChoosePosition) {
                mPointY = pointY
            } else {
                canvas.drawText(mLetters[i].substring(0, 1), mPointX, pointY, mLetterPaint)
            }
        }
    }

    /**
     * 绘制选中的字母
     */
    private fun drawSelectedLetter(canvas: Canvas) {
        if (mChoosePosition != -1) {
            // 绘制右侧选中字符
            mSelectedLetterPaint.reset()
            mSelectedLetterPaint.run {
                textSize = mSelectedTextSize.toFloat()
                color = if (isSlide) mCircleTextBgColor else mSelectedTextColor
                textAlign = Paint.Align.CENTER
                typeface = Typeface.DEFAULT_BOLD
            }
            canvas.drawText(
                mLetters[mChoosePosition].substring(0, 1),
                mPointX,
                mPointY,
                mSelectedLetterPaint
            )
        }
        // 绘制提示字符
        if (mRatio >= 0.9f) {
            val target = mLetters[mChoosePosition].substring(0, 1)
            val fontMetrics = mSelectedLetterPaint.fontMetrics
            val baseline = abs(-fontMetrics.bottom - fontMetrics.top)
            val x = mCircleCenterX
            val y = mCenterY + baseline / 2
            canvas.drawText(target, x, y, mSelectedLetterPaint)
        }
    }

    /**
     * 绘制波浪
     */
    private fun drawWavePath(canvas: Canvas) {
        mWavePath.reset()
        // 移动到起始点
        mWavePath.moveTo(mWidth.toFloat(), mCenterY - 3f * mRadius)

        //计算上部控制点的Y轴位置
        val controlTopY: Float = mCenterY - 2f * mRadius

        //计算上部结束点的坐标
        val endTopX: Float = (mWidth - mRadius * cos(ANGLE) * mRatio).toFloat()
        val endTopY: Float = (controlTopY + mRadius * sin(ANGLE)).toFloat()
        mWavePath.quadTo(mWidth.toFloat(), controlTopY, endTopX, endTopY)

        //计算中心控制点的坐标
        val controlCenterX: Float = (mWidth - 1.8f * mRadius * sin(ANGLE_R) * mRatio).toFloat()
        val controlCenterY: Float = mCenterY.toFloat()
        //计算下部结束点的坐标
        val controlBottomY: Float = mCenterY + 2f * mRadius
        val endBottomX: Float = endTopX
        val endBottomY: Float = (controlBottomY - mRadius * cos(ANGLE)).toFloat()
        mWavePath.quadTo(controlCenterX, controlCenterY, endBottomX, endBottomY)

        mWavePath.quadTo(
            mWidth.toFloat(),
            controlBottomY,
            mWidth.toFloat(),
            controlBottomY + mRadius
        )

        mWavePath.close()
        canvas.drawPath(mWavePath, mWavePaint)
    }

    private fun startAnimator(value: Float) {
        if (mRatioAnimator == null) {
            mRatioAnimator = ValueAnimator()
        }
        mRatioAnimator?.let {
            it.cancel()
            it.setFloatValues(value)
            it.addUpdateListener { v ->
                mRatio = v.animatedValue as Float
                //球弹到位的时候，并且点击的位置变了，即点击的时候显示当前选择位置
                if (mRatio == 1f && mOldPosition != mNewPosition) {
                    if (mNewPosition >= 0 && mNewPosition < mLetters.size) {
                        mChoosePosition = mNewPosition
                        mListener?.onLetterChange(mLetters[mNewPosition])
                    }
                }
                invalidate()
            }
            it.start()
        }
    }

    /**
     * 绘制左边提示的圆
     */
    private fun drawCirclePath(canvas: Canvas) {
        //x轴的移动路径
        mCircleCenterX = (mWidth + mCircleRadius) - (2f * mRadius + 2f * mCircleRadius) * mRatio
        mCirclePath.reset()
        mCirclePath.addCircle(
            mCircleCenterX,
            mCenterY.toFloat(),
            mCircleRadius.toFloat(),
            Path.Direction.CW
        )
        mCirclePath.op(mWavePath, Path.Op.DIFFERENCE)
        mCirclePath.close()
        canvas.drawPath(mCirclePath, mWavePaint)
    }

    /**
     * 设置当前选中
     */
    fun setCurrentPos(pos: Int) {
        if (pos >= mLetters.size) return
        mChoosePosition = pos
        invalidate()
    }

    fun getLetters(): List<String> {
        return mLetters
    }

    fun setLetters(letters: List<String>) {
        mLetters = letters
    }

    fun setOnTouchLetterChangeListener(listener: OnTouchLetterChangeListener) {
        mListener = listener
    }

    interface OnTouchLetterChangeListener {
        fun onLetterChange(letter: String)
    }
}